package org.ecloud.encrypt;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.ecloud.common.constants.StringPool;
import org.ecloud.common.exception.BaseException;
import org.ecloud.utils.FileUtil;

/** 
 * <pre>
 * 加密算法。 <br>
 * 1.MD5 <br>
 * 2.SHA-256 <br>
 * 3.对称加解密算法。
 * </pre>
 *
 * <pre> 
 * project: ecloud-utils
 * author: eddy
 * email: xqxyxchy@126.com
 * date: 2018年3月5日-下午9:01:32
 * rights: eddy
 * </pre>
 */
public class EncryptUtil {
	
	private EncryptUtil(){}
	
	/**
	 * 使用MD5加密 字符串
	 * 
	 * @param inStr
	 * @return
	 * @throws Exception
	 */
	public static String encryptMd5(String inStr) {
		return encryptMd5(inStr.getBytes());
	}

	/**
	 * 对String进行md5加密
	 *
	 * @param bytes
	 * @return
	 * @throws Exception
	 */
	public static String encryptMd5(byte[] bytes) {
		return DigestUtils.md5Hex(bytes);
	}

	/**
	 * 使用MD5加密 指定文件路径<br>
	 * String fileName = "e:\\e1.sql";<br>
	 * String str = encryptFileMd5(fileName);
	 * 
	 * @param fileName
	 * @return
	 * @throws FileNotFoundException
	 * @throws Exception
	 */
	public static String encryptFileMd5(String fileName) throws FileNotFoundException {
		FileInputStream is = new FileInputStream(fileName);
		return encryptMd5(is);
	}

	/**
	 * 使用MD5加密<br>
	 * 
	 * @return
	 * @throws Exception
	 */
	public static String encryptMd5(InputStream is) {
		return encryptMd5(FileUtil.readByte(is));
	}

	/**
	 * 
	 * 获取MD5加密
	 *
	 * @param is
	 * @return
	 * @throws IOException
	 */
	public static String encryptFileMd5(InputStream is) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		IOUtils.copy(is, out);
		return EncryptUtil.encryptMd5(out.toByteArray());
	}

	/**
	 * 输出明文按sha-256加密后的密文
	 * 
	 * @param inputStr
	 *            明文
	 * @return
	 */
	public static synchronized String encryptSha256(String inputStr) {
		try {
			MessageDigest md = MessageDigest.getInstance("SHA-256");
			byte[] digest = md.digest(inputStr.getBytes(StringPool.UTF_8));
			return new String(org.apache.commons.codec.binary.Base64.encodeBase64(digest));
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 *
	 *
	 * @param b
	 * @return
	 */
	public static String byte2hex(byte[] b) {
		StringBuilder hs = new StringBuilder();
		String stmp = "";

		for (int n = 0; n < b.length; n++) {
			stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
			if (stmp.length() == 1) {
				hs.append("0").append(stmp);
			} else {
				hs.append(stmp);
			}
		}
		return hs.toString().toLowerCase();
	}

	/**
	 * 默认密钥
	 */
	private static final String DEFAULT_KEY = ")(@#!@~&";
	
	  /** 
     * 密钥算法 
    */  
    private static final String KEY_ALGORITHM = "DES";  
	/**
	 * 默认的密码算法
	 */
    private static final String DEFAULT_CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";  

	/**
	 * 
	 * 对称解密算法
	 *
	 * @param message
	 * @param key
	 *            解密Key
	 * @return
	 * @throws Exception 
	 */
	public static String decrypt(String message, String key) {
		String result = "";
		try {
			byte[] bytesrc = stringToBytes(message);
			Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
			DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(StringPool.UTF_8));
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
			SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
			IvParameterSpec iv = new IvParameterSpec(key.getBytes(StringPool.UTF_8));
			cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
			byte[] retByte = cipher.doFinal(bytesrc);
			result = new String(retByte, StringPool.UTF_8);
		} catch (Exception e) {
			throw new BaseException(e.getMessage(), e.getCause());
		}
		return result;
	}

	/**
	 * 对称解密算法(默认key)
	 * 
	 * @param message
	 *            解密字符串
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(String message) {
		return decrypt(message, DEFAULT_KEY);
	}

	/**
	 * 
	 * 对称加密算法
	 *
	 * @param message
	 *            加密字符串
	 * @param key
	 *            加密key
	 * @return
	 * @throws Exception
	 */
	public static String encrypt(String message, String key) {
		byte[] retByte = new byte[]{};
		try {
			Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
			DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(StringPool.UTF_8));
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
			SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
			IvParameterSpec iv = new IvParameterSpec(key.getBytes(StringPool.UTF_8));
			cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
			retByte = cipher.doFinal(message.getBytes(StringPool.UTF_8));
		} catch (Exception e) {
			throw new BaseException(e.getMessage(), e.getCause());
		}
		return bytesToString(retByte);
	}

	/**
	 * 对称加密算法(默认key)
	 * 
	 * @param message
	 * @return
	 * @throws Exception
	 */
	public static String encrypt(String message) {
		return encrypt(message, DEFAULT_KEY);
	}

	/**
	 * String转Byte数组
	 * 
	 * @param temp
	 * @return
	 */
	public static byte[] stringToBytes(String temp) {
		byte[] digest = new byte[temp.length() / 2];
		for (int i = 0; i < digest.length; i++) {
			String byteString = temp.substring(2 * i, 2 * i + 2);
			int byteValue = Integer.parseInt(byteString, 16);
			digest[i] = (byte) byteValue;
		}
		return digest;
	}

	/**
	 * Byte数组转String
	 * 
	 * @param b
	 * @return
	 */
	public static String bytesToString(byte[] b) {
		StringBuilder hexString = new StringBuilder();
		for (int i = 0; i < b.length; i++) {
			String plainText = Integer.toHexString(0xff & b[i]);
			if (plainText.length() < 2)
				plainText = "0" + plainText;
			hexString.append(plainText);
		}
		return hexString.toString();
	}

}
